using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System;

//[ExecuteInEditMode]
public class Level : MonoBehaviour {
	
	public int tileWidth = 40;
	public int tileHeight = 30;
	public Tile[,] tiles;
	
	public GameObject tileRoot;
	public GameObject tilePrefab;
	
	//public bool toLoadLevel = false;
	//public string levelPath;
	
	//public bool toDuplicateTilePrefab;
	//public int tileNum = 50;
	
    public int Width
    {
       get { return tiles.GetLength(0); }
    }

    public int Height
    {
        get { return tiles.GetLength(1); }
    }
	
	// Use this for initialization
	
	public bool toLoadFile = false;
	public string fileName;
	public string levelEventFilename;
	public bool loadOver = false;
	
	public List<Vector2> exitPointList = new List<Vector2>();
	public string nextLevel;
	
	public List<LevelEvent> levelEventList = new List<LevelEvent>();
	private Dictionary<int, Vector2> levelEventNoIndexDic = new Dictionary<int, Vector2>();
	
	#region Audio
	public GameObject audioRoot;
	private List<AudioSource> audioSourceList = new List<AudioSource>();
	#endregion
	
	void Start()
	{
	
	}
	
	// Update is called once per frame
	void Update()
	{
		/*if(toLoadLevel)
		{
			toLoadLevel = false;
			LoadLevel(levelPath);
		}*/
		
		/*if(toDuplicateTilePrefab)
		{
			List<Transform> transformToRemove = new List<Transform>();
			for(int i = 0; i < tileRoot.transform.childCount; ++i)
			{
				transformToRemove.Add(tileRoot.transform.GetChild(i));
			}
			for(int i = 0; i < transformToRemove.Count; ++i)
			{
				transformToRemove[i].parent = null;
				MonoBehaviour.Destroy(transformToRemove[i].gameObject);
			}
			
			toDuplicateTilePrefab = false;
			
			for(int i = 0; i < tileNum; ++i)
			{
				GameObject newTileGameObject = (GameObject)GameObject.Instantiate(tilePrefab);
				newTileGameObject.name = "Tile" + i.ToString();
				newTileGameObject.transform.parent = tileRoot.transform;
				
				newTileGameObject.transform.localScale = new Vector3(1, 1, 1);
			}
			tileRoot.GetComponent<UIGrid>().Reposition();
		}*/
		
		if(toLoadFile)
		{
			loadOver = true;
			toLoadFile = false;
			LoadLevel(fileName);
			LoadLevelEvent(levelEventFilename);
		}
	}
	
	public TileCollision GetCollision(int x, int y)
    {
        // Prevent escaping past the level ends.
        if (x < 0 || x >= Width)
            return TileCollision.Impassable;
        // Allow jumping past the level top and falling through the bottom.
        if (y < 0 || y >= Height)
            return TileCollision.Passable;

        return tiles[x, y].tileCollision;
    }
	    
	public Rectangle GetBounds(int x, int y)
    {
		return tiles[x,y].GetBounds();
        //return new Rectangle(x * tileWidth, -y * tileHeight, tileWidth, tileHeight);
    }
	
	public bool isHorizontalBlock(int x, int y)
	{
		if(x - 1 < Width && x - 1 >= 0 && y < Height && y > 0)
		{	
			if(tiles[x - 1, y].tileCollision == TileCollision.Impassable)
				return true;
		}
		if(x + 1 < Width && x + 1 >= 0 && y < Height && y > 0)
		{	
			if(tiles[x + 1, y].tileCollision == TileCollision.Impassable)
				return true;
		}
		return false;
	}
	
	public bool isVerticalBlock(int x, int y)
	{
		if(x < Width && x >= 0 && y - 1 < Height && y - 1 > 0)
		{	
			if(tiles[x, y - 1].tileCollision == TileCollision.Impassable)
				return true;
		}
		if(x < Width && x >= 0 && y + 1 < Height && y + 1> 0)
		{	
			if(tiles[x, y + 1].tileCollision == TileCollision.Impassable)
				return true;
		}
		return false;
	}
	
	public void PlayAudio(string inputFileName, Vector2 centerPosition)
	{
		GameObject audioSource = new GameObject();
		audioSource.transform.parent = audioRoot.transform;
		audioSource.name = inputFileName;
		audioSource.transform.localPosition = new Vector3(centerPosition.x, centerPosition.y, 0);
		audioSource.transform.localScale = new Vector3(1, 1, 1);
		AudioSource newAS = audioSource.AddComponent<AudioSource>();
		newAS.clip = (AudioClip)Resources.Load("music/" + inputFileName, typeof(AudioClip));
		//newAS.clip = (AudioClip)Resources.LoadAssetAtPath("Assets/Resource/music/" + inputFileName, typeof(AudioClip));
		newAS.loop = true;
		newAS.Play();
		
		audioSourceList.Add(newAS);
	}
	
	public void UpdateAudiouSource(Vector2 playerPosition)
	{
		for(int i = 0; i < audioSourceList.Count; ++i)
		{
			//audioSourceList[i].volume = Vector2.Distance(audioSourceList[i].transform.localPosition, playerPosition);
			float distance = Vector2.Distance(audioSourceList[i].transform.localPosition, playerPosition);
			
			if(distance <= 100.0f)
				audioSourceList[i].volume = 1.0f;
			else
				audioSourceList[i].volume = (300.0f - distance) / 200.0f;
			//Debug.LogError("distance = " + distance.ToString());
		}
	}
	
	private void LoadLevelEvent(string inputLevelEventPath)
	{		
		XmlDocument levelEventDocument = new XmlDocument();
		
		//levelEventDocument.Load(inputLevelEventPath);

		TextAsset textAsset = (TextAsset)Resources.Load(inputLevelEventPath);
		using(MemoryStream ms = new MemoryStream(textAsset.bytes))
		{
			levelEventDocument.Load(ms);
			
			XmlNode rootNode = levelEventDocument.FirstChild;
			nextLevel = rootNode.SelectSingleNode("NextLevel").InnerText;
			
			levelEventList = new List<LevelEvent>();
			
			XmlNode levelEventsRootNode = rootNode.SelectSingleNode("LevelEvents");
			XmlNodeList levelEventNodeList = levelEventsRootNode.SelectNodes("LevelEvent");
			for(int i = 0; i < levelEventNodeList.Count; ++i)
			{
				
				string type = levelEventNodeList[i].SelectSingleNode("Type").InnerText;
				int radius = Convert.ToInt32(levelEventNodeList[i].SelectSingleNode("Radius").InnerText);
				
				if(type == "Music")
				{
					MusicPlayerLevelEvent newEvent = new MusicPlayerLevelEvent();
					newEvent.relatedLevel = this;
					newEvent.centerPosition = tiles[(int)levelEventNoIndexDic[i].x ,(int)levelEventNoIndexDic[i].y].GetBounds().Center;
					newEvent.radius = radius;
					newEvent.fileName = levelEventNodeList[i].SelectSingleNode("fileName").InnerText;
					levelEventList.Add(newEvent);
				}
				
			}
		}
	}
	
	private void LoadLevel(string inputLevelPath)
	{
		int width;
        List<string> lines = new List<string>();
		
		TextAsset textAsset = (TextAsset)Resources.Load(inputLevelPath);
		
        //using (StreamReader reader = new StreamReader(inputLevelPath))
        using(StreamReader reader = new StreamReader(new MemoryStream(textAsset.bytes)))
		{
			Debug.Log("LoadLevel Success");
            string line = reader.ReadLine();
            width = line.Length;
            while (line != null)
            {
                lines.Add(line);
                if (line.Length != width)
                    Debug.LogError(string.Format("The length of line {0} is different from all preceeding lines.", lines.Count));
                line = reader.ReadLine();
            }
        }

         // Allocate the tile grid.
         tiles = new Tile[width, lines.Count];
		
		
		List<Transform> transformToRemove = new List<Transform>();
			for(int i = 0; i < tileRoot.transform.childCount; ++i)
			{
				transformToRemove.Add(tileRoot.transform.GetChild(i));
			}
			for(int i = 0; i < transformToRemove.Count; ++i)
			{
				transformToRemove[i].parent = null;
				MonoBehaviour.Destroy(transformToRemove[i].gameObject);
			}
		
         // Loop over every tile position,
         /*for (int y = 0; y < Height; ++y)
         {
             for (int x = 0; x < Width; ++x)
             {
                 // to load each tile.
                 char tileType = lines[y][x];
                 tiles[x, y] = LoadTile(tileType, x, y);
             }
         }*/

         // Verify that the level has a beginning and an end.
         /*if (Player == null)
             throw new NotSupportedException("A level must have a starting point.");
         if (exit == InvalidPosition)
             throw new NotSupportedException("A level must have an exit.");*/

			
			//for(int i = 0; i < tileNum; ++i)
		for (int y = 0; y < Height; ++y)
        {
			for (int x = 0; x < Width; ++x)
            {
				char tileType = lines[y][x];
				
				GameObject newTileGameObject = (GameObject)GameObject.Instantiate(tilePrefab);
				//newTileGameObject.name = "Tile" + (x + y * Width).ToString();
				newTileGameObject.name = "Tile" + (x + y * Width).ToString() + "_" + x.ToString("D2") + y.ToString("D2");
				newTileGameObject.transform.parent = tileRoot.transform;
				
				newTileGameObject.transform.localScale = new Vector3(1, 1, 1);
				
				if(tileType == 'X')
				{
					exitPointList.Add(new Vector2(x, y));
				}
				else if(tileType >= '0' && tileType <= '9')
				{
				    //Debug.LogError("levelEventNoIndexDic added " + tileType.ToString());
					levelEventNoIndexDic.Add(tileType - '0', new Vector2(x, y));
				}
				
				newTileGameObject.GetComponent<Tile>().Init(tileType);
				tiles[x, y] = newTileGameObject.GetComponent<Tile>();
			}
		}
		tileRoot.GetComponent<UIGrid>().maxPerLine = Width;
		tileRoot.GetComponent<UIGrid>().Reposition();
		
		
		/*for (int y = 0; y < Height; ++y)
        {
			for (int x = 0; x < Width; ++x)
            {
				Debug.Log(string.Format("X {0} Y {1} Collision {2}", x, y, tiles[x, y].tileCollision));
			}
		}*/
	}
	
}
